package stone926.mods.more_enchantments.spawn.trade;

import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentLevelEntry;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.item.*;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtList;
import net.minecraft.nbt.NbtString;
import net.minecraft.util.DyeColor;
import net.minecraft.util.Util;
import net.minecraft.village.TradeOffer;
import net.minecraft.village.TradeOfferList;
import org.jetbrains.annotations.NotNull;
import stone926.mods.more_enchantments.MoreEnchantmentsMod;
import stone926.mods.more_enchantments.mixins.accessors.SpawnEggItemAccessor;
import stone926.mods.more_enchantments.util.BlockUtil;
import stone926.mods.more_enchantments.util.EnchantmentUtil;
import stone926.mods.more_enchantments.util.RandomUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import static stone926.mods.more_enchantments.MoreEnchantmentsMod.BUTCHER;


public class ZombieVillagerTradeOffers {

  public static final List<Enchantment> TREASURE_WARES = new ArrayList<>(EnchantmentUtil.LEGENDARY_ENCHANTMENTS) {{
    add(MoreEnchantmentsMod.THUNDER);
    add(MoreEnchantmentsMod.ONSLAUGHT);
    add(MoreEnchantmentsMod.STARVE);
  }};

  public static final List<Enchantment> NORMAL_WARES = new ArrayList<>(EnchantmentUtil.EFFECT_ENCHANTMENTS);

  public static final List<Item> COOKED_FISH = List.of(Items.COOKED_COD, Items.COOKED_SALMON);

  public static TradeOfferList LIBRARIAN(Random random) {
    Enchantment treasure = Util.getRandom(TREASURE_WARES, random);
    Enchantment normal = Util.getRandom(NORMAL_WARES, random);
    int rarity = 1;
    Item head = switch (random.nextInt(10)) {
      case 0, 1, 2, 3, 4 -> Items.CREEPER_HEAD;                 // 5
      case 5 -> Items.ZOMBIE_HEAD;                              // 1
      case 6 -> Items.SKELETON_SKULL;                           // 1
      case 7, 8, 9 -> {
        rarity = random.nextBoolean() ? 3 : 4;
        yield Items.DRAGON_HEAD;
      }  // 3
      default -> Items.DIRT;
    };
    TradeOfferList tradeOfferList = new TradeOfferList();
    tradeOfferList.add(new TradeOffer(
      new ItemStack(head, 64 / rarity),
      new ItemStack(Items.BOOKSHELF, 2),
      EnchantedBookItem.forEnchantment(
        new EnchantmentLevelEntry(treasure, RandomUtil.nextInt(treasure.getMaxLevel(), random))
      ), 1, 30, 0.15F
    ));
    tradeOfferList.add(new TradeOffer(
      new ItemStack(MoreEnchantmentsMod.CORNEL_ITEM, 64),
      new ItemStack(Items.BOOK, RandomUtil.nextInt(3, random)),
      EnchantedBookItem.forEnchantment(
        new EnchantmentLevelEntry(normal, RandomUtil.nextInt(normal.getMaxLevel(), random))
      ), 2, 30, 0.1F
    ));
    return tradeOfferList;
  }

  public static TradeOfferList CLERIC(Random random) {
    return new TradeOfferList() {{
      if (random.nextBoolean()) {
        add(new TradeOffer(
          new ItemStack(MoreEnchantmentsMod.COMPRESSED_SPIRITUAL_STUFFS, RandomUtil.nextInt(5, 13, random)),
          new ItemStack(MoreEnchantmentsMod.APPLE_OF_REDEMPTION_SINGLE),
          3, 100, 0.1F
        ));
      } else {
        add(new TradeOffer(
          new ItemStack(MoreEnchantmentsMod.COMPRESSED_SPIRITUAL_STUFFS, RandomUtil.nextInt(5, 15, random)),
          new ItemStack(MoreEnchantmentsMod.APPLE_OF_REDEMPTION_RANGE),
          3, 100, 0.1F
        ));
      }
      RandomUtil.runIfPossible(0.3, random, () -> add(new TradeOffer(
        new ItemStack(MoreEnchantmentsMod.COMPRESSED_SPIRITUAL_STUFFS, 1),
        new ItemStack(MoreEnchantmentsMod.EXPERIENCE_CONVERTER, RandomUtil.nextInt(1, 10, random)),
        10, 100, 0.1F
      )));
      RandomUtil.runIfPossible(0.15, random, () -> add(new TradeOffer(
        new ItemStack(MoreEnchantmentsMod.COMPRESSED_SPIRITUAL_STUFFS, RandomUtil.nextInt(10, 20, random)),
        new ItemStack(Items.ENCHANTED_GOLDEN_APPLE, 1),
        10, 200, 0.6F
      )));
    }};
  }

  public static TradeOfferList ARMORER(Random random) {
    return new TradeOfferList() {{
      add(new TradeOffer(
        new ItemStack(MoreEnchantmentsMod.CORNEL_ITEM, RandomUtil.nextInt(25, 40, random)),
        Util.getRandom(new ArrayList<>() {{
          add(new ItemStack(Items.NETHERITE_HELMET));
          add(new ItemStack(Items.NETHERITE_CHESTPLATE));
          add(new ItemStack(Items.NETHERITE_LEGGINGS));
          add(new ItemStack(Items.NETHERITE_BOOTS));
        }}, random), 3, 30, 0.1F
      ));
    }};
  }

  public static TradeOfferList TOOLSMITH(Random random) {
    return new TradeOfferList() {{
      add(new TradeOffer(
        new ItemStack(MoreEnchantmentsMod.CORNEL_ITEM, RandomUtil.nextInt(25, 40, random)),
        Util.getRandom(new ArrayList<>() {{
          add(new ItemStack(Items.NETHERITE_PICKAXE));
          add(new ItemStack(Items.NETHERITE_AXE));
          add(new ItemStack(Items.NETHERITE_HOE));
          add(new ItemStack(Items.NETHERITE_SHOVEL));
        }}, random), 3, 40, 0.1F
      ));
    }};
  }

  public static TradeOfferList WEAPONSMITH(Random random) {
    return new TradeOfferList() {{
      add(new TradeOffer(
        new ItemStack(MoreEnchantmentsMod.CORNEL_ITEM, RandomUtil.nextInt(25, 40, random)),
        Util.getRandom(new ArrayList<>() {{
          add(new ItemStack(Items.NETHERITE_SWORD));
          add(new ItemStack(Items.NETHERITE_AXE));
          add(new ItemStack(MoreEnchantmentsMod.WITHER_SKULL_BOW));
          add(new ItemStack(MoreEnchantmentsMod.FIREBALL_BOW));
          add(new ItemStack(MoreEnchantmentsMod.SHULKER_BOW));
        }}, random), 3, 40, 0.1F
      ));
    }};
  }

  public static TradeOfferList BUTCHER(Random random) {
    List<SpawnEggItem> spawnEggItems = SpawnEggItemAccessor.getSpawnEggs().values().stream().toList();
    return new TradeOfferList() {{
      for (int i = 0; i < RandomUtil.nextInt(1, 5, random); i++) {
        add(new TradeOffer(
          EnchantedBookItem.forEnchantment(new EnchantmentLevelEntry(BUTCHER, RandomUtil.nextInt(BUTCHER.getMaxLevel(), random))),
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(20, 64, random)),
          new ItemStack(Util.getRandom(spawnEggItems, random)), 10, 40, 0.1F
        ));
      }
      RandomUtil.runIfPossible(0.3, random, () -> {
        ItemStack axolotl = new ItemStack(Items.AXOLOTL_BUCKET);
        axolotl.getOrCreateNbt().putInt("Variant", RandomUtil.nextInt(0, 4, random));
        add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(20, 40, random)), axolotl,
          10, 40, 0.1F
        ));
      });
    }};
  }

  public static TradeOfferList FISHERMAN(Random random) {
    return new TradeOfferList() {{
      add(new TradeOffer(
        new ItemStack(Items.EMERALD, RandomUtil.nextInt(4, 6, random)),
        new ItemStack(Util.getRandom(COOKED_FISH, random), RandomUtil.nextInt(3, 7, random)),
        new ItemStack(BlockUtil.getRandomCoralBlock(random), RandomUtil.nextInt(2, 6, random)),
        10, 20, 0.03F
      ));
      RandomUtil.runFunctionsIfPossible(
        0.4, random,
        () -> add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(3, 15, random)),
          new ItemStack(Util.getRandom(COOKED_FISH, random), RandomUtil.nextInt(1, 3, random)),
          new ItemStack(BlockUtil.getRandomCoral(random), RandomUtil.nextInt(3, 6, random)),
          10, 20, 0.03F
        )),
        () -> add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(3, 15, random)),
          new ItemStack(Util.getRandom(COOKED_FISH, random), RandomUtil.nextInt(2, 5, random)),
          new ItemStack(BlockUtil.getRandomDeadCoral(random), RandomUtil.nextInt(1, 6, random)),
          10, 30, 0.03F
        )),
        () -> add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(3, 15, random)),
          new ItemStack(Util.getRandom(COOKED_FISH, random), RandomUtil.nextInt(3, 6, random)),
          new ItemStack(BlockUtil.getRandomCoralFans(random), RandomUtil.nextInt(1, 3, random)),
          10, 30, 0.03F
        )),
        () -> add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(3, 15, random)),
          new ItemStack(Util.getRandom(COOKED_FISH, random), RandomUtil.nextInt(3, 6, random)),
          new ItemStack(BlockUtil.getRandomDeadCoralFans(random), RandomUtil.nextInt(1, 3, random)),
          10, 30, 0.03F
        )),
        () -> add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(3, 15, random)),
          new ItemStack(Util.getRandom(COOKED_FISH, random), RandomUtil.nextInt(3, 6, random)),
          new ItemStack(BlockUtil.getRandomCoralBlock(random), RandomUtil.nextInt(1, 3, random)),
          10, 30, 0.03F
        )),
        () -> add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(3, 15, random)),
          new ItemStack(Util.getRandom(COOKED_FISH, random), RandomUtil.nextInt(3, 6, random)),
          new ItemStack(BlockUtil.getRandomDeadCoralBlock(random), RandomUtil.nextInt(1, 3, random)),
          10, 30, 0.03F
        ))
      );
      RandomUtil.runIfPossible(0.3, random, () -> add(new TradeOffer(
        new ItemStack(Items.EMERALD, RandomUtil.nextInt(3, 10, random)),
        new ItemStack(Util.getRandom(COOKED_FISH, random), RandomUtil.nextInt(5, 15, random)),
        new ItemStack(Items.SEA_LANTERN, RandomUtil.nextInt(1, 3, random)),
        10, 20, 0.03F
      )));
      RandomUtil.runIfPossible(0.55, random, () -> add(new TradeOffer(
        new ItemStack(Util.getRandom(COOKED_FISH, random), RandomUtil.nextInt(1, 2, random)),
        new ItemStack(Items.SEA_PICKLE, RandomUtil.nextInt(5, 20, random)),
        10, 20, 0.03F
      )));
      RandomUtil.runIfPossible(0.45, random, () -> add(new TradeOffer(
        new ItemStack(Util.getRandom(COOKED_FISH, random), RandomUtil.nextInt(2, 4, random)),
        new ItemStack(Items.SEAGRASS, RandomUtil.nextInt(6, 20, random)),
        10, 20, 0.03F
      )));
      RandomUtil.runIfPossible(0.25, random, () -> add(new TradeOffer(
        new ItemStack(Items.EMERALD, RandomUtil.nextInt(7, 20, random)),
        new ItemStack(Util.getRandom(COOKED_FISH, random), RandomUtil.nextInt(3, 15, random)),
        new ItemStack(Items.CONDUIT, RandomUtil.nextInt(1, 2, random)),
        5, 20, 0.1F
      )));
    }};
  }

  public static TradeOfferList FARMER(Random random) {
    return new TradeOfferList() {{
      add(new TradeOffer(
        new ItemStack(Items.EMERALD, RandomUtil.nextInt(5, 15, random)),
        new ItemStack(Items.POISONOUS_POTATO, RandomUtil.nextInt(3, 10, random)),
        new ItemStack(Items.DIRT_PATH, RandomUtil.nextInt(3, 10, random)),
        10, 20, 0.03F
      ));
      add(new TradeOffer(
        new ItemStack(Items.EMERALD, RandomUtil.nextInt(5, 15, random)),
        new ItemStack(Items.POISONOUS_POTATO, RandomUtil.nextInt(3, 10, random)),
        new ItemStack(Items.FARMLAND, RandomUtil.nextInt(3, 10, random)),
        10, 20, 0.03F
      ));
      RandomUtil.runFunctionsIfPossible(
        0.5, random,
        () -> add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(5, 10, random)),
          new ItemStack(Items.POISONOUS_POTATO, RandomUtil.nextInt(3, 10, random)),
          new ItemStack(Items.PODZOL, RandomUtil.nextInt(3, 10, random)),
          10, 20, 0.05F
        )),
        () -> add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(5, 10, random)),
          new ItemStack(Items.POISONOUS_POTATO, RandomUtil.nextInt(3, 10, random)),
          new ItemStack(Items.COARSE_DIRT, RandomUtil.nextInt(3, 10, random)),
          10, 20, 0.05F
        )),
        () -> add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(6, 18, random)),
          new ItemStack(Items.POISONOUS_POTATO, RandomUtil.nextInt(3, 6, random)),
          new ItemStack(Items.HAY_BLOCK, RandomUtil.nextInt(3, 13, random)),
          10, 20, 0.07F
        ))
      );
      RandomUtil.runFunctionsIfPossible(
        0.8, random,
        () -> add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(2, 7, random)),
          new ItemStack(Items.POISONOUS_POTATO, RandomUtil.nextInt(2, 4, random)),
          new ItemStack(Items.DEAD_BUSH, RandomUtil.nextInt(10, 30, random)),
          10, 20, 0.05F
        )),
        () -> add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(2, 7, random)),
          new ItemStack(Items.POISONOUS_POTATO, RandomUtil.nextInt(2, 4, random)),
          new ItemStack(Items.FERN, RandomUtil.nextInt(10, 30, random)),
          10, 20, 0.05F
        )),
        () -> add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(2, 7, random)),
          new ItemStack(Items.POISONOUS_POTATO, RandomUtil.nextInt(2, 4, random)),
          new ItemStack(Items.LARGE_FERN, RandomUtil.nextInt(10, 30, random)),
          10, 20, 0.05F
        )),
        () -> add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(2, 7, random)),
          new ItemStack(Items.POISONOUS_POTATO, RandomUtil.nextInt(2, 4, random)),
          new ItemStack(Items.GRASS, RandomUtil.nextInt(10, 30, random)),
          10, 20, 0.07F
        ))
      );
    }};
  }

  public static TradeOfferList LEATHERWORKER(Random random) {
    final List<Item> HORSE_ARMORS = List.of(
      Items.IRON_HORSE_ARMOR, Items.GOLDEN_HORSE_ARMOR, Items.DIAMOND_HORSE_ARMOR, Items.LEATHER_HORSE_ARMOR
    );
    return new TradeOfferList() {{
      add(new TradeOffer(
        new ItemStack(Items.LEATHER, RandomUtil.nextInt(10, 64, random)),
        EnchantmentUtil.enchant(
          new ItemStack(Util.getRandom(HORSE_ARMORS, random)),
          Enchantments.PROTECTION, RandomUtil.nextInt(Enchantments.PROTECTION.getMaxLevel() + 3, random)
        ), 1, 20, 0.1F
      ));
    }};
  }

  public static TradeOfferList SHEPHERD(Random random) {
    return new TradeOfferList() {{
      ItemStack dye = new ItemStack(DyeItem.byColor(Util.getRandom(DyeColor.values(), random)), RandomUtil.nextInt(1, 4, random));
      add(new TradeOffer(
        new ItemStack(Items.EMERALD, RandomUtil.nextInt(5, 15, random)), dye,
        5, 20, 0.05F
      ));
      for (int i = 0; i < RandomUtil.nextInt(0, 3, random); i++) {
        if (random.nextBoolean()) {
          add(new TradeOffer(
            new ItemStack(Items.EMERALD, RandomUtil.nextInt(15, 25, random)),
            new ItemStack(BlockUtil.getRandomWoolBlock(random), RandomUtil.nextInt(1, 20, random)),
            5, 20, 0.05F
          ));
        } else {
          add(new TradeOffer(
            new ItemStack(Items.EMERALD, RandomUtil.nextInt(15, 25, random)),
            new ItemStack(Items.MUTTON, RandomUtil.nextInt(1, 4, random)),
            new ItemStack(BlockUtil.getRandomWoolBlock(random), RandomUtil.nextInt(1, 20, random)),
            5, 20, 0.05F
          ));
        }
      }
      RandomUtil.runIfPossible(0.5, random, () -> add(new TradeOffer(
        new ItemStack(Items.SHEEP_SPAWN_EGG, RandomUtil.nextInt(5, 15, random)),
        new ItemStack(Items.EMERALD, 64),
        1, 100, 0.1F
      )));
    }};
  }

  public static TradeOfferList MASON(Random random) {
    return new TradeOfferList() {{
      add(new TradeOffer(
        new ItemStack(MoreEnchantmentsMod.COMPRESSED_STONE_ITEM, 64),
        new ItemStack(Items.EMERALD_BLOCK, RandomUtil.nextInt(10, 20, random)),
        new ItemStack(Items.SPAWNER), 2, 50, 0.2F
      ));
      List<TradeOffer> tradeOffers = List.of(
        new TradeOffer(
          new ItemStack(MoreEnchantmentsMod.COMPRESSED_STONE_ITEM, 64),
          new ItemStack(Items.EMERALD_BLOCK, 64),
          new ItemStack(Items.BEDROCK), 1, 100, 2F
        ),
        new TradeOffer(
          new ItemStack(MoreEnchantmentsMod.COMPRESSED_STONE_ITEM, 64),
          new ItemStack(Items.EMERALD_BLOCK, 64),
          new ItemStack(Items.STRUCTURE_VOID), 1, 100, 2F
        ),
        new TradeOffer(
          new ItemStack(MoreEnchantmentsMod.COMPRESSED_STONE_ITEM, 64),
          new ItemStack(Items.EMERALD_BLOCK, 64),
          new ItemStack(Items.COMMAND_BLOCK), 1, 100, 2F
        ),
        new TradeOffer(
          new ItemStack(MoreEnchantmentsMod.COMPRESSED_STONE_ITEM, 64),
          new ItemStack(Items.EMERALD_BLOCK, 64),
          new ItemStack(Items.STRUCTURE_BLOCK), 1, 100, 2F
        ),
        new TradeOffer(
          new ItemStack(MoreEnchantmentsMod.COMPRESSED_STONE_ITEM, 64),
          new ItemStack(Items.EMERALD_BLOCK, 64),
          new ItemStack(Items.JIGSAW), 1, 100, 2F
        ),
        new TradeOffer(
          new ItemStack(MoreEnchantmentsMod.COMPRESSED_STONE_ITEM, 64),
          new ItemStack(Items.EMERALD_BLOCK, 64),
          new ItemStack(Items.BARRIER), 1, 100, 2F
        )
      );
      RandomUtil.runIfPossible(0.1, random, () -> add(Util.getRandom(tradeOffers, random)));
    }};
  }

  public static TradeOfferList FLETCHER(Random random) {
    return new TradeOfferList() {{
      add(new TradeOffer(
        new ItemStack(Items.EMERALD, RandomUtil.nextInt(20, 35, random)),
        new ItemStack(MoreEnchantmentsMod.WITHER_SKULL_GUNPOWDER, RandomUtil.nextInt(32, 64, random)),
        10, 10, 0.1F
      ));
      add(new TradeOffer(
        new ItemStack(Items.EMERALD, RandomUtil.nextInt(20, 35, random)),
        new ItemStack(MoreEnchantmentsMod.MIXED_GUNPOWDER, RandomUtil.nextInt(32, 64, random)),
        10, 10, 0.1F
      ));
      add(new TradeOffer(
        new ItemStack(Items.EMERALD, RandomUtil.nextInt(20, 35, random)),
        new ItemStack(MoreEnchantmentsMod.SHULKER_GUNPOWDER, RandomUtil.nextInt(32, 64, random)),
        10, 10, 0.1F
      ));
    }};
  }

  public static @NotNull TradeOfferList CARTOGRAPHER(Random random) {
    return new TradeOfferList() {{
      add(new TradeOffer(
        new ItemStack(Items.EMERALD, RandomUtil.nextInt(10, 25, random)),
        new ItemStack(
          BlockUtil.getRandomGlassBlock(random), RandomUtil.nextInt(1, 5, random)
        ), 20, 50, 0.04F
      ));
      add(new TradeOffer(
        new ItemStack(Items.EMERALD, RandomUtil.nextInt(8, 20, random)),
        new ItemStack(
          BlockUtil.getRandomPaneBlock(random), RandomUtil.nextInt(1, 8, random)
        ), 20, 50, 0.04F
      ));
      RandomUtil.runIfPossible(0.5, random, () -> add(new TradeOffer(
        new ItemStack(Items.EMERALD, RandomUtil.nextInt(10, 13, random)),
        new ItemStack(Items.WRITABLE_BOOK),
        5, 70, 0.1F
      )));
      RandomUtil.runIfPossible(0.8, random, () -> {
        ItemStack knowledgeBook = new ItemStack(Items.KNOWLEDGE_BOOK);
        NbtCompound nbtCompound = knowledgeBook.getOrCreateNbt();
        NbtList nbtList = new NbtList();
        if (random.nextBoolean()) {
          nbtList.add(NbtString.of(MoreEnchantmentsMod.id("compressed_spiritual_stuffs").toString()));
        } else {
          nbtList.add(NbtString.of(MoreEnchantmentsMod.id("compressed_stone").toString()));
        }
        nbtCompound.put("Recipes", nbtList);
        add(new TradeOffer(
          new ItemStack(Items.EMERALD, RandomUtil.nextInt(25, 40, random)), knowledgeBook,
          5, 70, 0.1F
        ));
      });
    }};
  }

}